From ec029aaa9a79965f83476808e32b8573891aa79c Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Sat, 23 Jul 2011 08:49:15 +0100 Subject: [PATCH] add privileged (dom0) kernel feature indication With our switching away from supporting 32-bit Dom0 operation, users complained that attempts (perhaps due to lack of knowledge of that change) to boot the no longer privileged kernel in Dom0 resulted in apparently silent failure. To make the mismatch explicit and visible, add dom0 feature flag that the kernel can set to indicate operation as dom0 is supported. Due to the way elf_xen_parse_features() worked up to now (getting fixed here), adding features indications to the old, string based ELF note would make the respective kernel unusable on older hypervisors. For that reason, a new ELF Note is being introduced that allows specifying supported features as a bit array instead (with features unknown to the hypervisor simply ignored, as now also done by elf_xen_parse_features(), whereas here unknown kernel-required features still keep the kernel [and hence VM] from booting). Introduce and use elf_note_numeric_array() to be forward compatible (or else an old hypervisor wouldn't be able to parse kernel specified features occupying more than 64 bits - thanks, Ian!). Signed-off-by: Jan Beulich --- tools/libxc/xc_dom_elfloader.c | 7 +++++++ xen/arch/ia64/xen/domain.c | 7 +++++++ xen/arch/x86/domain_build.c | 7 +++++++ xen/common/kernel.c | 2 ++ xen/common/libelf/libelf-dominfo.c | 13 +++++++++++-- xen/common/libelf/libelf-tools.c | 21 +++++++++++++++++++++ xen/include/public/elfnote.h | 15 ++++++++++++++- xen/include/public/features.h | 5 ++++- xen/include/xen/libelf.h | 2 ++ 9 files changed, 75 insertions(+), 4 deletions(-) diff --git a/tools/libxc/xc_dom_elfloader.c b/tools/libxc/xc_dom_elfloader.c index 9114bfb333..906e3a2f07 100644 --- a/tools/libxc/xc_dom_elfloader.c +++ b/tools/libxc/xc_dom_elfloader.c @@ -286,6 +286,13 @@ static int xc_dom_parse_elf_kernel(struct xc_dom_image *dom) if ( (rc = elf_xen_parse(elf, &dom->parms)) != 0 ) return rc; + if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms.f_required) ) + { + xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not" + " support unprivileged (DomU) operation", __FUNCTION__); + return -EINVAL; + } + /* find kernel segment */ dom->kernel_seg.vstart = dom->parms.virt_kstart; dom->kernel_seg.vend = dom->parms.virt_kend; diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 271a744e87..957c288710 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -2164,6 +2164,13 @@ int __init construct_dom0(struct domain *d, return -1; } + if (parms.elf_notes[XEN_ELFNOTE_FEATURES].type != XEN_ENT_NONE && + !test_bit(XENFEAT_dom0, parms.f_supported)) + { + printk("Kernel does not support Dom0 operation\n"); + return -1; + } + p_start = parms.virt_base; pkern_start = parms.virt_kstart; pkern_end = parms.virt_kend; diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index cbb92699f7..8d58291c33 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -415,6 +415,13 @@ int __init construct_dom0( return -EINVAL; } + if ( parms.elf_notes[XEN_ELFNOTE_FEATURES].type != XEN_ENT_NONE && + !test_bit(XENFEAT_dom0, parms.f_supported) ) + { + printk("Kernel does not support Dom0 operation\n"); + return -EINVAL; + } + #if defined(__x86_64__) if ( compat32 ) { diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 5558dc0712..7decc1d70d 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -287,6 +287,8 @@ DO(xen_version)(int cmd, XEN_GUEST_HANDLE(void) arg) (1U << XENFEAT_auto_translated_physmap); if ( supervisor_mode_kernel ) fi.submap |= 1U << XENFEAT_supervisor_mode_kernel; + if ( current->domain == dom0 ) + fi.submap |= 1U << XENFEAT_dom0; #ifdef CONFIG_X86 if ( !is_hvm_vcpu(current) ) fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) | diff --git a/xen/common/libelf/libelf-dominfo.c b/xen/common/libelf/libelf-dominfo.c index 57ca26088b..c569a4893a 100644 --- a/xen/common/libelf/libelf-dominfo.c +++ b/xen/common/libelf/libelf-dominfo.c @@ -26,7 +26,8 @@ static const char *const elf_xen_feature_names[] = { [XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables", [XENFEAT_auto_translated_physmap] = "auto_translated_physmap", [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel", - [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb" + [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb", + [XENFEAT_dom0] = "dom0" }; static const int elf_xen_features = sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]); @@ -83,7 +84,7 @@ int elf_xen_parse_features(const char *features, } } } - if ( i == elf_xen_features ) + if ( i == elf_xen_features && required && feature[0] == '!' ) return -1; } @@ -114,6 +115,7 @@ int elf_xen_parse_note(struct elf_binary *elf, [XEN_ELFNOTE_LOADER] = { "LOADER", 1}, [XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1}, [XEN_ELFNOTE_FEATURES] = { "FEATURES", 1}, + [XEN_ELFNOTE_SUPPORTED_FEATURES] = { "SUPPORTED_FEATURES", 0}, [XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1}, [XEN_ELFNOTE_SUSPEND_CANCEL] = { "SUSPEND_CANCEL", 0 }, [XEN_ELFNOTE_MOD_START_PFN] = { "MOD_START_PFN", 0 }, @@ -122,6 +124,7 @@ int elf_xen_parse_note(struct elf_binary *elf, const char *str = NULL; uint64_t val = 0; + unsigned int i; int type = elf_uval(elf, note, type); if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) || @@ -200,6 +203,12 @@ int elf_xen_parse_note(struct elf_binary *elf, return -1; break; + case XEN_ELFNOTE_SUPPORTED_FEATURES: + for ( i = 0; i < XENFEAT_NR_SUBMAPS; ++i ) + parms->f_supported[i] |= elf_note_numeric_array( + elf, note, sizeof(*parms->f_supported), i); + break; + } return 0; } diff --git a/xen/common/libelf/libelf-tools.c b/xen/common/libelf/libelf-tools.c index 885d5e8ad3..cb97908138 100644 --- a/xen/common/libelf/libelf-tools.c +++ b/xen/common/libelf/libelf-tools.c @@ -227,6 +227,27 @@ uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note) return 0; } } + +uint64_t elf_note_numeric_array(struct elf_binary *elf, const elf_note *note, + unsigned int unitsz, unsigned int idx) +{ + const void *desc = elf_note_desc(elf, note); + int descsz = elf_uval(elf, note, descsz); + + if ( descsz % unitsz || idx >= descsz / unitsz ) + return 0; + switch (unitsz) + { + case 1: + case 2: + case 4: + case 8: + return elf_access_unsigned(elf, desc, idx * unitsz, unitsz); + default: + return 0; + } +} + const elf_note *elf_note_next(struct elf_binary *elf, const elf_note * note) { int namesz = (elf_uval(elf, note, namesz) + 3) & ~3; diff --git a/xen/include/public/elfnote.h b/xen/include/public/elfnote.h index 2159c04907..42d76da877 100644 --- a/xen/include/public/elfnote.h +++ b/xen/include/public/elfnote.h @@ -178,10 +178,23 @@ */ #define XEN_ELFNOTE_MOD_START_PFN 16 +/* + * The features supported by this kernel (numeric). + * + * Other than XEN_ELFNOTE_FEATURES on pre-4.2 Xen, this note allows a + * kernel to specify support for features that older hypervisors don't + * know about. The set of features 4.2 and newer hypervisors will + * consider supported by the kernel is the combination of the sets + * specified through this and the string note. + * + * LEGACY: FEATURES + */ +#define XEN_ELFNOTE_SUPPORTED_FEATURES 17 + /* * The number of the highest elfnote defined. */ -#define XEN_ELFNOTE_MAX XEN_ELFNOTE_MOD_START_PFN +#define XEN_ELFNOTE_MAX XEN_ELFNOTE_SUPPORTED_FEATURES /* * System information exported through crash notes. diff --git a/xen/include/public/features.h b/xen/include/public/features.h index 0e3c486249..b4533ccc0b 100644 --- a/xen/include/public/features.h +++ b/xen/include/public/features.h @@ -75,7 +75,10 @@ #define XENFEAT_hvm_safe_pvclock 9 /* x86: pirq can be used by HVM guests */ -#define XENFEAT_hvm_pirqs 10 +#define XENFEAT_hvm_pirqs 10 + +/* operation as Dom0 is supported */ +#define XENFEAT_dom0 11 #define XENFEAT_NR_SUBMAPS 1 diff --git a/xen/include/xen/libelf.h b/xen/include/xen/libelf.h index 584d8b3b2d..9de84eb267 100644 --- a/xen/include/xen/libelf.h +++ b/xen/include/xen/libelf.h @@ -179,6 +179,8 @@ const elf_sym *elf_sym_by_index(struct elf_binary *elf, int index); const char *elf_note_name(struct elf_binary *elf, const elf_note * note); const void *elf_note_desc(struct elf_binary *elf, const elf_note * note); uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note); +uint64_t elf_note_numeric_array(struct elf_binary *, const elf_note *, + unsigned int unitsz, unsigned int idx); const elf_note *elf_note_next(struct elf_binary *elf, const elf_note * note); int elf_is_elfbinary(const void *image); -- 2.30.2